Shared Memory Specs
For programmers out there--this is how I've done the shared memory and external input.
The memory is shared in the file mappings: "fceu.GameMemBlock" (128k), "fceu.RAM" (2k), "fceu.BotInput" (4k), "fceu.XBuf" (the graphics buffer) (256*256+8), "fceu.ROM" (varies), "fceu.VROM" (varies). Probably the RAM and the BotInput are the only things you'll need to open.
You will want to use OpenFileMapping to get the data. This is a Windows NT kernel function, and so should be available under this name (or a very similar name) in whatever programming language you are using. Example in C/C++:
#include "windows.h" int main(int argc, char* argv[]) { HANDLE mapBotInput; unsigned int * BotInput; //Get the shared memory mapBotInput = OpenFileMapping(FILE_MAP_ALL_ACCESS, false, "fceu.BotInput"); if(!mapBotInput) { //Error } //Get a pointer to it BotInput = (unsigned int *) MapViewOfFile(mapBotInput, FILE_MAP_WRITE, 0, 0, 0); if(!BotInput) { //Error } //Now BotInput[] is available for reading/writing. //Cleanup UnmapViewOfFile(mapBotInput); CloseHandle(mapBotInput); BotInput = NULL; }
The external input is read from fceu.BotInput. This is an array of 1024 uint32s. I'll use BotInput[x] to refer to the x-th value (0-based). A value of '0' in BotInput[0] means it's safe to write to BotInput. BotInput[1] through [1023] store the input in chronological order. The input format is: high word = 1 means load state (low word ignored currently), high word = 0 means 1 frame of input, where the 4th byte is controller 1 and the 3rd is controller 2. After writing the input, write the length of the input (i.e. the highest x such that BotInput[x] contains data) in BotInput[0]. (This is a good place to let your program idle, so windows will give the CPU to FCEU!) Then FCEU will run the input, writing '0' to BotInput[0] when it's done. Code is probably more explanatory:
if(BotInput[0]) { BotPointer++; switch(BotInput[BotPointer] >> 16) { case 0: joy[0] = BotInput[BotPointer] & 255; joy[1] = BotInput[BotPointer] >> 8; joy[2] = joy[3] = 0; FCEUI_FrameAdvance(); break; case 1: FCEUI_LoadState(0); break; default: break; } if(BotPointer >= BotInput[0] || BotPointer >= 1023) { BotInput[0] = 0; BotPointer = 0; } }For the controller button values:
#define JOY_A 1 #define JOY_B 2 #define JOY_SELECT 4 #define JOY_START 8 #define JOY_UP 0x10 #define JOY_DOWN 0x20 #define JOY_LEFT 0x40 #define JOY_RIGHT 0x80
If you're confused by "high word" and "low word" or whatver, note that LoadState is just a value of 65536, player 1 A is 1, player 1 right is 128, player 2 A is 256, player 2 right is 32768.
I recommend always loading the save state when you start your bot, so you know where you're starting from!
Example bot code:
BotInput[1] = 65536; //Load state BotInput[2] = 1; //First frame = player 1 A BotInput[3] = 2; //Second frame = player 1 B BotInput[4] = 3; //Third frame = player 1 AB BotInput[0] = 4; //Tell FCEU to read 4 values from BotInput while(BotInput[0] != 0) //Wait for FCEU to write 0 to BotInput[0] { Sleep(1); //It's a good idea to idle while you wait. } //Now you can write to BotInput again.